﻿//IStreamWrapper.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Plaza.Wrappers
{
	using System;

	/// <summary>
	/// Состояние потока репликации.
	/// </summary>
	enum StreamWrapperStates
	{
		/// <summary>
		/// Поток закрыт.
		/// </summary>
		Closed = 0,

		/// <summary>
		/// Поток в состоянии получения снэпшота из локальной БД клиента репликации.
		/// </summary>
		LocalSnapshot = 1,

		/// <summary>
		/// Поток в состоянии получения снэпшота от сервера репликации.
		/// </summary>
		RemoveSnapshot = 2,

		/// <summary>
		/// Поток в состоянии получения онлайн-данных от сервера репликации.
		/// </summary>
		Online = 3,

		/// <summary>
		/// Поток закрыт после получения всех требуемых данных.
		/// </summary>
		Complete = 4,

		/// <summary>
		/// Поток переоткрыт и клиент будет получать все данные заново. 
		/// </summary>
		ReOpenned = 5,

		/// <summary>
		/// Ошибка.
		/// </summary>
		Error = 6,
	}

	/// <summary>
	/// Поток репликационных данных.
	/// </summary>
	interface IStreamWrapper
	{
		/// <summary>
		/// Закрытие потока.
		/// </summary>
		void Close();

		/// <summary>
		/// Открытие потока репликационных данных.
		/// </summary>
		/// <param name="conn">Указатель на интерфейс соединения.</param>
		void Open(IConnectionWrapper conn);

		/// <summary>
		/// Строка соединения с БД.
		/// </summary>
		string ConnectionString { get; set; }

		/// <summary>
		/// Тип потока репликации.
		/// </summary>
		PlazaStreamReplicationTypes Type { get; set; }

		/// <summary>
		/// Имя потока репликации.
		/// </summary>
		string StreamName { get; set; }

		/// <summary>
		/// Состояние потока репликации.
		/// </summary>
		StreamWrapperStates State { get; }

		/// <summary>
		/// Набор таблиц в схеме репликации. 
		/// </summary>
		ITableSetWrapper TableSet { get; set; }

		/// <summary>
		/// Нотификация начала транзакции по обработке пакета данных от сервера репликации.
		/// </summary>
		event Action<IStreamWrapper> StreamDataBegin;

		/// <summary>
		/// Нотификация окончания транзакции по обработке пакета данных от сервера репликации.
		/// </summary>
		event Action<IStreamWrapper> StreamDataEnd;

		/// <summary>
		/// Нотификация об удалении всех записей из БД с ревижином меньше минимального серверного.
		/// </summary>
		event Action<IStreamWrapper, string, long> StreamDatumDeleted;

		/// <summary>
		/// Нотификация об удалении записи из БД.
		/// </summary>
		event Action<IStreamWrapper, string, long, IRecordWrapper> StreamDataDeleted;

		/// <summary>
		/// Нотификация об изменении состояния потока репликационных данных.
		/// </summary>
		event Action<IStreamWrapper, StreamWrapperStates> StreamStateChanged;

		/// <summary>
		/// Нотификация о вставке записи в БД.
		/// </summary>
		event Action<IStreamWrapper, string, IRecordWrapper> StreamDataInserted;

		/// <summary>
		/// Нотификация об изменении записи в БД. Для безбазового клиента нотификация Update не приходит.
		/// </summary>
		event Action<IStreamWrapper, string, long, IRecordWrapper> StreamDataUpdated;

		/// <summary>
		/// Нотификация изменения номера жизни в серверной схеме репликации.
		/// </summary>
		event Action<IStreamWrapper, int> StreamLifeNumChanged;
	}

	class StreamWrapper32 : IStreamWrapper
	{
		private readonly P2ClientGateMTA32.CP2DataStream _stream;

		public StreamWrapper32()
		{
			_stream = new P2ClientGateMTA32.CP2DataStream();

			_stream.StreamDataBegin += a => StreamDataBegin(this);
			_stream.StreamDataEnd += a => StreamDataEnd(this);
			_stream.StreamDatumDeleted += (a, b, c) => StreamDatumDeleted(this, b, c);
			_stream.StreamDataDeleted += (a, b, c, d) => StreamDataDeleted(this, b, c, new RecordWrapper32(d));
			_stream.StreamStateChanged += (a, b) => StreamStateChanged(this, (StreamWrapperStates)b);
			_stream.StreamDataInserted += (a, b, c) => StreamDataInserted(this, b, new RecordWrapper32(c));
			_stream.StreamDataUpdated += (a, b, c, d) => StreamDataUpdated(this, b, c, new RecordWrapper32(d));
			_stream.StreamLifeNumChanged += (a, b) => StreamLifeNumChanged(this, b);
		}

		public void Close()
		{
			_stream.Close();
		}

		public void Open(IConnectionWrapper conn)
		{
			var c = (ConnectionWrapper32)conn;
			_stream.Open(c.Connection);
		}

		public string ConnectionString
		{
			get { return _stream.DBConnString; }
			set { _stream.DBConnString = value; }
		}

		public PlazaStreamReplicationTypes Type
		{
			get { return (PlazaStreamReplicationTypes)_stream.type; }
			set { _stream.type = (P2ClientGateMTA32.TRequestType)value; }
		}

		public string StreamName
		{
			get { return _stream.StreamName; }
			set { _stream.StreamName = value; }
		}

		public StreamWrapperStates State
		{
			get { return (StreamWrapperStates)_stream.State; }
		}

		private ITableSetWrapper _tableSet;

		public ITableSetWrapper TableSet
		{
			get { return _tableSet; }
			set
			{
				_tableSet = value;
				_stream.TableSet = ((TableSetWrapper32)value).TableSet;
			}
		}

		public event Action<IStreamWrapper> StreamDataBegin;
		public event Action<IStreamWrapper> StreamDataEnd;
		public event Action<IStreamWrapper, string, long> StreamDatumDeleted;
		public event Action<IStreamWrapper, string, long, IRecordWrapper> StreamDataDeleted;
		public event Action<IStreamWrapper, StreamWrapperStates> StreamStateChanged;
		public event Action<IStreamWrapper, string, IRecordWrapper> StreamDataInserted;
		public event Action<IStreamWrapper, string, long, IRecordWrapper> StreamDataUpdated;
		public event Action<IStreamWrapper, int> StreamLifeNumChanged;
	}

	class StreamWrapper64 : IStreamWrapper
	{
		private readonly P2ClientGateMTA64.CP2DataStream _stream;

		public StreamWrapper64()
		{
			_stream = new P2ClientGateMTA64.CP2DataStream();

			_stream.StreamDataBegin += a => StreamDataBegin(this);
			_stream.StreamDataEnd += a => StreamDataEnd(this);
			_stream.StreamDatumDeleted += (a, b, c) => StreamDatumDeleted(this, b, c);
			_stream.StreamDataDeleted += (a, b, c, d) => StreamDataDeleted(this, b, c, new RecordWrapper64(d));
			_stream.StreamStateChanged += (a, b) => StreamStateChanged(this, (StreamWrapperStates)b);
			_stream.StreamDataInserted += (a, b, c) => StreamDataInserted(this, b, new RecordWrapper64(c));
			_stream.StreamDataUpdated += (a, b, c, d) => StreamDataUpdated(this, b, c, new RecordWrapper64(d));
			_stream.StreamLifeNumChanged += (a, b) => StreamLifeNumChanged(this, b);
		}

		public void Close()
		{
			_stream.Close();
		}

		public void Open(IConnectionWrapper conn)
		{
			var c = (ConnectionWrapper64)conn;
			_stream.Open(c.Connection);
		}

		public string ConnectionString
		{
			get { return _stream.DBConnString; }
			set { _stream.DBConnString = value; }
		}

		public PlazaStreamReplicationTypes Type
		{
			get { return (PlazaStreamReplicationTypes)_stream.type; }
			set { _stream.type = (P2ClientGateMTA64.TRequestType)value; }
		}

		public string StreamName
		{
			get { return _stream.StreamName; }
			set { _stream.StreamName = value; }
		}

		public StreamWrapperStates State
		{
			get { return (StreamWrapperStates)_stream.State; }
		}

		private ITableSetWrapper _tableSet;

		public ITableSetWrapper TableSet
		{
			get { return _tableSet; }
			set
			{
				_tableSet = value;
				_stream.TableSet = ((TableSetWrapper64)value).TableSet;
			}
		}

		public event Action<IStreamWrapper> StreamDataBegin;
		public event Action<IStreamWrapper> StreamDataEnd;
		public event Action<IStreamWrapper, string, long> StreamDatumDeleted;
		public event Action<IStreamWrapper, string, long, IRecordWrapper> StreamDataDeleted;
		public event Action<IStreamWrapper, StreamWrapperStates> StreamStateChanged;
		public event Action<IStreamWrapper, string, IRecordWrapper> StreamDataInserted;
		public event Action<IStreamWrapper, string, long, IRecordWrapper> StreamDataUpdated;
		public event Action<IStreamWrapper, int> StreamLifeNumChanged;
	}
}